﻿#include <Sys\RenderUnit\SysRenderDatagram\VERTEXRD.HPP>
#include <Render\Render_Win32\Render_Win32_OpenGL\RENDER_WIN32_OPENGL.HPP>
#include <Sys\RenderUnit\SYSDDCLASSID.HPP>
// #include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\VERTEXDDOPENGL.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\VERTEXREGISTRYDDOPENGL.HPP>
#include <Sys\RenderUnit\SysDatagramDisposal_OpenGL\STAGEDDPENGL.HPP>


using namespace CxxlMan;
using namespace Cxxl3D;


// IDatagramDisposal 寄存在 IDepositStore 的資料
class CDDDeposit:public IDDDeposit
{
  GLuint m_VertexBufferID;
  GLuint m_IndexBufferID;

  C3D_USINT m_VertexNum, m_IndexNum;

  // 取得實作類別，為了避免轉形太花時間
  virtual void *GetInstance()
  {
    return this;
  }

public:
  // Constructor
  CDDDeposit(GLuint VertexBufferID, GLuint IndexBufferID, C3D_USINT VertexNum, C3D_USINT IndexNum)
  {
    m_VertexBufferID = VertexBufferID;
    m_IndexBufferID = IndexBufferID;
    m_VertexNum = VertexNum;
    m_IndexNum = IndexNum;
  }

  // Destructor
  virtual ~CDDDeposit()
  {
  	if ( m_VertexBufferID )
		  glDeleteBuffers(1, &m_VertexBufferID);

  	if ( m_IndexBufferID )
      glDeleteBuffers(1, &m_IndexBufferID);
  }

  GLuint cxxlFASTCALL GetVertexBufferID()
  {
    return m_VertexBufferID;
  }

  GLuint cxxlFASTCALL GetIndexBufferID()
  {
    return m_IndexBufferID;
  }

  void cxxlFASTCALL Get_VertexNum_IndexNum(C3D_USINT &VertexNum, C3D_USINT &IndexNum)
  {
    VertexNum = m_VertexNum;
    IndexNum = m_IndexNum;
  }
};


template <typename VERTEXFMT>
class CVertexDD:public IVertexDD
{
  // 頂點數量和索引數量，主要供 CTriagleDDOpenGL.cpp 取用
  C3D_USINT m_VertexNum, m_IndexNum;

  // 頂點數量和索引數量，主要供 CTriagleDDOpenGL.cpp 取用
  void cxxlFASTCALL Get_VertexNum_IndexNum(C3D_USINT &VertexNum, C3D_USINT &IndexNum)
  {
    VertexNum = m_VertexNum;
    IndexNum = m_IndexNum;
  }

  // 一個頂點結構的大小，主要供 CMutiTextureDDOpenGL.cpp 取用
  GLsizei cxxlFASTCALL Get_VertexSize()
  {
    return m_VertexSize;
  }

protected:

  // 一個頂點結構的大小，主要供 CMutiTextureDDOpenGL.cpp 取用
  GLsizei m_VertexSize;

  Smart_Ptr<CDDDeposit> CDDDeposit_Ptr;
  Smart_Ptr<IVertexRD<VERTEXFMT> > IVertexRD_Ptr;
  Smart_Ptr<IVertexRegistryDDOpenGL> IVertexRegistryDDOpenGL_Ptr;

  Smart_Ptr<IStageDDOpenGL> m_IStageDDOpenGL_Ptr;


  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {
    // 第一次被叫用才會取得
    if(IVertexRegistryDDOpenGL_Ptr.isNULL())
      IVertexRegistryDDOpenGL_Ptr =  Smart_Cast<IVertexRegistryDDOpenGL>(IRenderDatagramDisposalCenter_Arg->GetIDatagramDisposal_OpenGL(IVertexRegistryOpenGL_ClassID));

    // 第一次被叫用才會取得
    if(m_IStageDDOpenGL_Ptr.isNULL())
      m_IStageDDOpenGL_Ptr = Smart_Cast<IStageDDOpenGL>(IRenderDatagramDisposalCenter_Arg->GetIDatagramDisposal_OpenGL(IStageOpenGL_ClassID));

    IVertexRegistryDDOpenGL_Ptr->Set(this); // 每次被叫用須設定

    Lock(IRenderDatagram_Arg);

    Smart_Ptr<DepositStore> DepositStore_Ptr = (IVertexRD<VERTEXFMT> *)IVertexRD_Ptr;
    Smart_Ptr<IDDDeposit> IDDDeposit_Ptr = GetDeposit(DepositStore_Ptr);
    if(IDDDeposit_Ptr.isNULL())
    {
      CSmart_Ptr<const tagVertex<VERTEXFMT> > Vertex_cPtr = IVertexRD_Ptr->GetVertexData();
      if(Vertex_cPtr.isNULL() == false)
      {
        C3D_USINT VertexNum, IndexNum;
        CSmart_Array<const VERTEXFMT> Vertex_Array = NULL;
        CSmart_Array<const C3D_USINT> Index_Array = NULL;
        Vertex_cPtr->GetData(VertexNum,Vertex_Array,IndexNum,Index_Array);

        if(VertexNum > 0 && Vertex_Array.isNULL() == false && IndexNum > 0 && Index_Array.isNULL() == false)
        {

          GLuint VertexBufferID = 0;
          GLuint IndexBufferID = 0;

          // 產生一塊新的 Vertex Buffer Object
          glGenBuffers(1, &VertexBufferID);
          // 使用 VertexBufferID 所代表的 Vertex Buffer Object
          glBindBuffer(GL_ARRAY_BUFFER, VertexBufferID);
          // 配置 Vertex Buffer 的大小, 並同時把 g_pSphereVertices 的內容拷具過進去.`
          glBufferData(GL_ARRAY_BUFFER, VertexNum * sizeof(VERTEXFMT), (const VERTEXFMT *)Vertex_Array, GL_STATIC_COPY);

          // 產生一塊新的 Index Buffer Object
          glGenBuffers(1, &IndexBufferID);
          // 使用 IndexBufferID 所代表的 Index Buffer Object
          glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferID);
          // 配置Index Buffer的大小, 並同時把g_pSphereIndices的內容拷具過去
          glBufferData(GL_ELEMENT_ARRAY_BUFFER, IndexNum * sizeof(C3D_USINT), (const C3D_USINT*)Index_Array, GL_STATIC_COPY);

          CDDDeposit_Ptr = new CDDDeposit(VertexBufferID, IndexBufferID, VertexNum, IndexNum);
          SetDeposit((CDDDeposit *)CDDDeposit_Ptr, DepositStore_Ptr);
        }
        else
          CDDDeposit_Ptr.Destroy(); // 不畫出
      }
      else
        CDDDeposit_Ptr.Destroy(); // 不畫出
    }
    else
      CDDDeposit_Ptr = (CDDDeposit *)IDDDeposit_Ptr->GetInstance();

    if(CDDDeposit_Ptr.isNULL() == false)
      CDDDeposit_Ptr->Get_VertexNum_IndexNum(m_VertexNum, m_IndexNum);

    UnLock(IRenderDatagram_Arg);

    return true;
  }

public:
  // Constrctor
  CVertexDD()
    :cxxlObject(Spirit_Easy),
    CDDDeposit_Ptr(NULL,this),
    IVertexRD_Ptr(NULL,this),
    IVertexRegistryDDOpenGL_Ptr(NULL,this),
    m_IStageDDOpenGL_Ptr(NULL,this)
  {
    m_VertexNum = m_IndexNum = 0;
  }

  // Destrctor
  virtual ~CVertexDD()
  {
  }

};


/*************************************************/

class CVertexDD_NC_OpenGL:public CVertexDD<tagVERTEXFMT_NC>
{
  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {
    IVertexRD_Ptr = (IVertexRD_NC*)GetDefaultInterface(IRenderDatagram_Arg);

    CVertexDD<tagVERTEXFMT_NC>::Exec(IRenderDatagramDisposalCenter_Arg,IRenderDatagram_Arg,ViewMatrix_Arg);

    if(CDDDeposit_Ptr.isNULL())
      return true; // 不畫出

  	// 使用 VertexBufferID 所代表的 Vertex Buffer Object
	  glBindBuffer(GL_ARRAY_BUFFER, CDDDeposit_Ptr->GetVertexBufferID());
  	// 使用 IndexBufferID 所代表的 Index Buffer Object
	  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, CDDDeposit_Ptr->GetIndexBufferID());


  	// 設定要用陣列的方式傳入頂點 位置 法向量 顏色
	  //glEnableClientState(GL_VERTEX_ARRAY);
    //glEnableClientState(GL_NORMAL_ARRAY);
  	//glEnableClientState(GL_COLOR_ARRAY);
    IRenderDatagramDisposalCenter_Arg->SetFVF(FVF_XYZ | FVF_DIFFUSE | FVF_NORMAL);

    

  	// VertexPointer/NormalPointer/ColorPointer 不再傳入指標位置
	  // 而是傳入記憶體相對的位移值
    int voffset = (int) &((tagVERTEXFMT_NC*)0)->Position;
    int noffset = (int) &((tagVERTEXFMT_NC*)0)->Normal;
    int coffset = (int) &((tagVERTEXFMT_NC*)0)->Color;


  	// 最後一個值是在記憶體中的起始位移
    m_VertexSize = sizeof(tagVERTEXFMT_NC);
  	glVertexPointer(3, GL_FLOAT, m_VertexSize, (GLvoid *)voffset); 
    glNormalPointer(GL_FLOAT, m_VertexSize, (GLvoid *)noffset);
	  glColorPointer(4, GL_UNSIGNED_BYTE, m_VertexSize, (GLvoid *)coffset); 
    
    return true;
  }

  // 為 Texture Stage 設定要用的 CoordIndex，主要供 CTexture2DDDOpenGL.cpp、CCubemapTextureDDOpenGL.cpp 叫用
  // 若不含 CoordIndex 回覆 false
  bool cxxlFASTCALL SetCoordIndex()
  {
    return false;
  }

public:

  // Constructor
  CVertexDD_NC_OpenGL()
    :cxxlObject(Spirit_Easy)
  {
  }

  // Destructor
  ~CVertexDD_NC_OpenGL()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CVertexDD_NC_OpenGL()
{
  return new CVertexDD_NC_OpenGL;
}

/**********************************************/

class CVertexDD_C_OpenGL:public CVertexDD<tagVERTEXFMT_C>
{
  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {

    IVertexRD_Ptr = (IVertexRD_C*)GetDefaultInterface(IRenderDatagram_Arg);

    CVertexDD<tagVERTEXFMT_C>::Exec(IRenderDatagramDisposalCenter_Arg,IRenderDatagram_Arg,ViewMatrix_Arg);

    if(CDDDeposit_Ptr.isNULL())
      return true; // 不畫出


  	// 使用 VertexBufferID 所代表的 Vertex Buffer Object
	  glBindBuffer(GL_ARRAY_BUFFER, CDDDeposit_Ptr->GetVertexBufferID());
  	// 使用 IndexBufferID 所代表的 Index Buffer Object
	  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, CDDDeposit_Ptr->GetIndexBufferID());


  	// 設定要用陣列的方式傳入頂點 位置 顏色
	  // glEnableClientState(GL_VERTEX_ARRAY);
  	// glEnableClientState(GL_COLOR_ARRAY);
    IRenderDatagramDisposalCenter_Arg->SetFVF(FVF_XYZ  | FVF_DIFFUSE);


  	// VertexPointer/ColorPointer不再傳入指標位置
	  // 而是傳入記憶體相對的位移值
    int voffset = (int) &((tagVERTEXFMT_C*)0)->Position;
    int coffset = (int) &((tagVERTEXFMT_C*)0)->Color;

  	// 最後一個值是在記憶體中的起始位移
    m_VertexSize = sizeof(tagVERTEXFMT_C);
  	glVertexPointer(3, GL_FLOAT, m_VertexSize, (GLvoid *)voffset); 
	  glColorPointer(4, GL_UNSIGNED_BYTE, m_VertexSize, (GLvoid *)coffset); 
    
    return true;
  }

  // 為 Texture Stage 設定要用的 CoordIndex，主要供 CTexture2DDDOpenGL.cpp、CCubemapTextureDDOpenGL.cpp 叫用
  // 若不含 CoordIndex 回覆 false
  bool cxxlFASTCALL SetCoordIndex()
  {
    return false;
  }

public:

  // Constructor
  CVertexDD_C_OpenGL()
    :cxxlObject(Spirit_Easy)
  {
  }

  // Destructor
  ~CVertexDD_C_OpenGL()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CVertexDD_C_OpenGL()
{
  return new CVertexDD_C_OpenGL;
}

/**********************************************/

class CVertexDD_N_OpenGL:public CVertexDD<tagVERTEXFMT_N>
{
  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {

    IVertexRD_Ptr = (IVertexRD_N*)GetDefaultInterface(IRenderDatagram_Arg);

    CVertexDD<tagVERTEXFMT_N>::Exec(IRenderDatagramDisposalCenter_Arg,IRenderDatagram_Arg,ViewMatrix_Arg);

    if(CDDDeposit_Ptr.isNULL())
      return true; // 不畫出


  	// 使用 VertexBufferID 所代表的 Vertex Buffer Object
	  glBindBuffer(GL_ARRAY_BUFFER, CDDDeposit_Ptr->GetVertexBufferID());
  	// 使用 IndexBufferID 所代表的 Index Buffer Object
	  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, CDDDeposit_Ptr->GetIndexBufferID());


  	// 設定要用陣列的方式傳入頂點 位置 法向量
	  //glEnableClientState(GL_VERTEX_ARRAY);
    //glEnableClientState(GL_NORMAL_ARRAY);
    IRenderDatagramDisposalCenter_Arg->SetFVF(FVF_XYZ | FVF_NORMAL);

  	// VertexPointer/NormalPointer不再傳入指標位置
	  // 而是傳入記憶體相對的位移值
    int voffset = (int) &((tagVERTEXFMT_N*)0)->Position;
    int noffset = (int) &((tagVERTEXFMT_N*)0)->Normal;

  	// 最後一個值是在記憶體中的起始位移
    m_VertexSize = sizeof(tagVERTEXFMT_N);
  	glVertexPointer(3, GL_FLOAT, m_VertexSize, (GLvoid *)voffset); 
    glNormalPointer(GL_FLOAT, m_VertexSize, (GLvoid *)noffset);
    
    return true;
  }

  // 為 Texture Stage 設定要用的 CoordIndex，主要供 CTexture2DDDOpenGL.cpp、CCubemapTextureDDOpenGL.cpp 叫用
  // 若不含 CoordIndex 回覆 false
  bool cxxlFASTCALL SetCoordIndex()
  {
    return false;
  }

public:

  // Constructor
  CVertexDD_N_OpenGL()
    :cxxlObject(Spirit_Easy)
  {
  }

  // Destructor
  ~CVertexDD_N_OpenGL()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CVertexDD_N_OpenGL()
{
  return new CVertexDD_N_OpenGL;
}

/**********************************************/

class CVertexDD_NT_OpenGL:public CVertexDD<tagVERTEXFMT_NT>
{
  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {

    IVertexRD_Ptr = (IVertexRD_NT*)GetDefaultInterface(IRenderDatagram_Arg);

    CVertexDD<tagVERTEXFMT_NT>::Exec(IRenderDatagramDisposalCenter_Arg,IRenderDatagram_Arg,ViewMatrix_Arg);

    if(CDDDeposit_Ptr.isNULL())
      return true; // 不畫出


  	// 使用 VertexBufferID 所代表的 Vertex Buffer Object
	  glBindBuffer(GL_ARRAY_BUFFER, CDDDeposit_Ptr->GetVertexBufferID());
  	// 使用 IndexBufferID 所代表的 Index Buffer Object
	  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, CDDDeposit_Ptr->GetIndexBufferID());


  	// 設定要用陣列的方式傳入頂點 位置 法向量 紋理uv
    IRenderDatagramDisposalCenter_Arg->SetFVF(FVF_XYZ | FVF_NORMAL | FVF_TEXTURE);

  	// VertexPointer/NormalPointer/TexCoordPointer 不再傳入指標位置
	  // 而是傳入記憶體相對的位移值
    int voffset = (int) &((tagVERTEXFMT_NT*)0)->Position;
    int noffset = (int) &((tagVERTEXFMT_NT*)0)->Normal;
    int toffset = (int) &((tagVERTEXFMT_NT*)0)->Texture;

  	// 最後一個值是在記憶體中的起始位移
    m_VertexSize = sizeof(tagVERTEXFMT_NT);
  	glVertexPointer(3, GL_FLOAT, m_VertexSize, (GLvoid *)voffset); 
    glNormalPointer(GL_FLOAT, m_VertexSize, (GLvoid *)noffset);
    // glClientActiveTexture(GL_TEXTURE0_ARB);
    // glEnableClientState(GL_TEXTURE_COORD_ARRAY); // 不知是不是須再加上這句
    glTexCoordPointer(2,GL_FLOAT,m_VertexSize,(GLvoid *)toffset);
    
    return true;
  }

  // 為 Texture Stage 設定要用的 CoordIndex，主要供 CTexture2DDDOpenGL.cpp、CCubemapTextureDDOpenGL.cpp 叫用
  // 若不含 CoordIndex 回覆 false
  bool cxxlFASTCALL SetCoordIndex()
  {
    unsigned int Stage = m_IStageDDOpenGL_Ptr->GetStage();
    if(Stage == 0)
      return true;

    int toffset = (int) &((tagVERTEXFMT_NT*)0)->Texture;

    glClientActiveTexture(GL_TEXTURE0_ARB+Stage);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);
    glTexCoordPointer(2,GL_FLOAT,m_VertexSize,(GLvoid *)toffset);
    return true;
  }

public:

  // Constructor
  CVertexDD_NT_OpenGL()
    :cxxlObject(Spirit_Easy)
  {
  }

  // Destructor
  ~CVertexDD_NT_OpenGL()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CVertexDD_NT_OpenGL()
{
  return new CVertexDD_NT_OpenGL;
}

/**********************************************/

class CVertexDD_T_OpenGL:public CVertexDD<tagVERTEXFMT_T>
{
  virtual bool cxxlFASTCALL Exec(const Smart_Ptr<IRenderDatagramDisposalCenterOpengl> &IRenderDatagramDisposalCenter_Arg,
    const Smart_Ptr<IRenderDatagram> &IRenderDatagram_Arg, const CxxlMan::CSmart_Ptr<Matrix4x4> &ViewMatrix_Arg)
  {

    IVertexRD_Ptr = (IVertexRD_T*)GetDefaultInterface(IRenderDatagram_Arg);

    CVertexDD<tagVERTEXFMT_T>::Exec(IRenderDatagramDisposalCenter_Arg,IRenderDatagram_Arg,ViewMatrix_Arg);

    if(CDDDeposit_Ptr.isNULL())
      return true; // 不畫出


  	// 使用 VertexBufferID 所代表的 Vertex Buffer Object
	  glBindBuffer(GL_ARRAY_BUFFER, CDDDeposit_Ptr->GetVertexBufferID());
  	// 使用 IndexBufferID 所代表的 Index Buffer Object
	  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, CDDDeposit_Ptr->GetIndexBufferID());


  	// 設定要用陣列的方式傳入頂點 位置 紋理uv
    IRenderDatagramDisposalCenter_Arg->SetFVF(FVF_XYZ | FVF_TEXTURE);

  	// VertexPointer/NormalPointer/TexCoordPointer 不再傳入指標位置
	  // 而是傳入記憶體相對的位移值
    int voffset = (int) &((tagVERTEXFMT_T*)0)->Position;
    int toffset = (int) &((tagVERTEXFMT_T*)0)->Texture;

  	// 最後一個值是在記憶體中的起始位移
    m_VertexSize = sizeof(tagVERTEXFMT_T);
  	glVertexPointer(3, GL_FLOAT, m_VertexSize, (GLvoid *)voffset);
    // glClientActiveTexture(GL_TEXTURE0_ARB);
    // glEnableClientState(GL_TEXTURE_COORD_ARRAY); // 不知是不是須再加上這句
    glTexCoordPointer(2,GL_FLOAT,m_VertexSize,(GLvoid *)toffset);
    
    return true;
  }

  // 為 Texture Stage 設定要用的 CoordIndex，主要供 CTexture2DDDOpenGL.cpp、CCubemapTextureDDOpenGL.cpp 叫用
  // 若不含 CoordIndex 回覆 false
  bool cxxlFASTCALL SetCoordIndex()
  {
    unsigned int Stage = m_IStageDDOpenGL_Ptr->GetStage();
    if(Stage == 0)
      return true;

    int toffset = (int) &((tagVERTEXFMT_T*)0)->Texture;
    glClientActiveTexture(GL_TEXTURE0_ARB+Stage);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY); 
    glTexCoordPointer(2,GL_FLOAT,m_VertexSize,(GLvoid *)toffset);
    return true;
  }

public:

  // Constructor
  CVertexDD_T_OpenGL()
    :cxxlObject(Spirit_Easy)    
  {
  }

  // Destructor
  ~CVertexDD_T_OpenGL()
  {
  }

};

cxxlObject *cxxlFASTCALL New_CVertexDD_T_OpenGL()
{
  return new CVertexDD_T_OpenGL;
}